#include <iostream>
#include <thread> //线程的头文件
#include <unistd.h>
#include <mutex>  //锁有关的头文件
#include <condition_variable> //条件变量有关的头文件
using namespace std;

/*
	创建5个线程，模拟售票窗口卖票
	主函数模拟铁道部，负责放票出来
	因为C++中的条件变量要求跟unique_lock配合使用(不是跟mutex直接配合使用)
	unique_lock有个特点：当你创建unique_lock的对象时，会自动上锁
*/

//定义全局变量用来票的总数
volatile int ticketnum=10;
//定义互斥锁
mutex mymutex;
//定义条件变量
condition_variable myval;

//线程任务函数1
void fun1()
{
	while(1)
	{
		unique_lock<mutex> ulock(mymutex); //自动上锁
		ticketnum--;
		if(ticketnum<=0) //票的数量为0
		{
			cout<<"线程1阻塞在wait这里了"<<endl;
			//阻塞当前线程，暂时停止售票
			myval.wait(ulock);
		}
		sleep(1);
		cout<<"窗口1卖出一张票，剩下: "<<ticketnum<<"张票"<<endl;
		ulock.unlock();
		usleep(500);
	}
}
//线程任务函数2
void fun2()
{
	while(1)
	{
		unique_lock<mutex> ulock(mymutex);
		ticketnum--;
		if(ticketnum<=0) //票的数量为0
		{
			cout<<"线程2阻塞在wait这里了"<<endl;
			//阻塞当前线程，暂时停止售票
			myval.wait(ulock);
		}
		sleep(1);
		cout<<"窗口2卖出一张票，剩下: "<<ticketnum<<"张票"<<endl;
		ulock.unlock();
		usleep(500);
	}
}
//线程任务函数3 
void fun3()
{
	while(1)
	{
		unique_lock<mutex> ulock(mymutex);
		ticketnum--;
		if(ticketnum<=0) //票的数量为0
		{
			cout<<"线程3阻塞在wait这里了"<<endl;
			//阻塞当前线程，暂时停止售票
			myval.wait(ulock);
		}
		sleep(1);
		cout<<"窗口3卖出一张票，剩下: "<<ticketnum<<"张票"<<endl;
		ulock.unlock();
		usleep(500);
	}
}
//线程任务函数4 
void fun4()
{
	while(1)
	{
		unique_lock<mutex> ulock(mymutex);
		ticketnum--;
		if(ticketnum<=0) //票的数量为0
		{
			cout<<"线程4阻塞在wait这里了"<<endl;
			//阻塞当前线程，暂时停止售票
			myval.wait(ulock);
		}
		sleep(1);
		cout<<"窗口4卖出一张票，剩下: "<<ticketnum<<"张票"<<endl;
		ulock.unlock();
		usleep(500);
	}
}
//线程任务函数5 
void fun5()
{
	while(1)
	{
		unique_lock<mutex> ulock(mymutex);
		ticketnum--;
		if(ticketnum<=0) //票的数量为0
		{
			cout<<"线程5阻塞在wait这里了"<<endl;
			//阻塞当前线程，暂时停止售票
			myval.wait(ulock);
		}
		sleep(1);
		cout<<"窗口5卖出一张票，剩下: "<<ticketnum<<"张票"<<endl;
		ulock.unlock();
		usleep(500);
	}
}
int main()
{
	//创建线程对象
	thread t1(fun1);
	thread t2(fun2);
	thread t3(fun3);
	thread t4(fun4);
	thread t5(fun5);
	
	//主函数代表铁道部
	while(1)
	{
		if(ticketnum<=0)
		{
			cout<<"铁道部领导，票卖完了，请您放点票出来"<<endl;
			int temp;
			cin>>temp;
			ticketnum=temp;
			//唤醒其中一个线程
			myval.notify_one();
		}
	}
	
	//线程回收
	t1.join();
	t2.join();
	t3.join();
	t4.join();
	t5.join();
	return 0;
}
